import json
import os
from pathlib import Path
from typing import Dict, Any, Optional
import argparse

from ..core.command.base import Command
from ..interfaces.merge_config import MergeConfigOptions, MergeConfigResult
from ..base.file_utils import FileUtils
from src.base.registry import bera
from src.base.sql_file_utils import SQLFileUtils

class MergeConfigCommand(Command):
    """配置合并命令"""

    def __init__(self):
        super().__init__()
        self.name = "merge-config"
        self.group = "配置管理"
        self.help = "合并配置文件"
        self.description = """
        合并配置文件，支持命名空间隔离。该命令会:
        1. 读取源目录中的所有配置文件
        2. 按照命名空间合并配置
        3. 将合并结果写入目标文件
        """

    def add_arguments(self, parser: argparse.ArgumentParser) -> None:
        """添加命令参数"""
        parser.add_argument(
            '--dir', '-d',
            required=True,
            help='源配置文件目录'
        )
        parser.add_argument(
            '--target', '-t',
            help='目标文件路径'
        )
        parser.add_argument(
            '--indent',
            type=int,
            default=2,
            help='JSON缩进空格数'
        )
        parser.add_argument(
            '--dry-run',
            action='store_true',
            help='只预览不写入文件'
        )

    def execute(self, args: argparse.Namespace) -> None:
        """执行命令"""
        result = merge_config(
            source_dir=args.dir,
            target=args.target,
            indent=args.indent,
            dry_run=args.dry_run
        )
        if result != 0:
            bera.logger.error("配置合并失败")
            raise Exception("配置合并失败")

def merge_config(
    source_dir: str,
    target: Optional[str] = None,
    indent: int = 2,
    dry_run: bool = False
) -> int:
    """
    合并配置文件命令

    Args:
        source_dir: 源配置文件目录
        target: 目标文件路径，如果不指定则使用默认路径
        indent: JSON缩进空格数
        dry_run: 是否只预览不写入文件

    Returns:
        int: 0表示成功，非0表示失败
    """
    try:
        options = MergeConfigOptions(
            source_dir=source_dir,
            target=target,
            indent=indent,
            dry_run=dry_run
        )
        result = _merge_config(options)
        if not result.success:
            bera.logger.error(f"配置合并失败: {result.message}")
            raise Exception("配置合并失败")
        return 0
    except Exception as e:
        bera.logger.error(f"配置合并失败: {str(e)}")
        SQLFileUtils.handle_file_error(e, Path(target) if target else None)

def _post_process(source_path: Path, merged_config: Dict[str, Any]) -> Dict[str, Any]:
    """
    合并后处理:根据sql.json的字段顺序重排序columns

    Args:
        source_path: 源目录路径
        merged_config: 合并后的配置

    Returns:
        Dict[str, Any]: 处理后的配置
    """
    # 获取sql.json路径
    sql_json_path = source_path / "sql.json"
    if not sql_json_path.exists():
        return merged_config

    try:
        # 读取sql.json
        with open(sql_json_path, 'r', encoding='utf-8') as f:
            sql_config = json.load(f)

        # 如果sql.json中没有columns,直接返回
        if 'columns' not in sql_config:
            return merged_config

        # 获取sql.json中的字段顺序
        sql_columns = list(sql_config['columns'].keys())

        # 创建新的有序columns字典
        ordered_columns = {}
        for column_name in sql_columns:
            if column_name in merged_config['columns']:
                ordered_columns[column_name] = merged_config['columns'][column_name]

        # 添加在sql.json中不存在但在merged_config中存在的字段
        for column_name in merged_config['columns']:
            if column_name not in ordered_columns:
                ordered_columns[column_name] = merged_config['columns'][column_name]

        # 更新merged_config
        merged_config['columns'] = ordered_columns

        return merged_config

    except Exception as e:
        bera.logger.warning(f"Post process failed: {str(e)}")
        return merged_config

def _merge_config(options: MergeConfigOptions) -> MergeConfigResult:
    """
    实现配置文件合并的核心逻辑

    Args:
        options: 合并配置的选项

    Returns:
        MergeConfigResult: 合并结果
    """
    # 验证源目录
    source_path = Path(options.source_dir)
    if not source_path.exists() or not source_path.is_dir():
        return MergeConfigResult(
            success=False,
            message=f"Source directory not found: {options.source_dir}"
        )

    # 检查目录是否为空
    json_files = list(source_path.glob("*.json"))
    if not json_files:
        return MergeConfigResult(
            success=False,
            message=f"Source directory is empty: {options.source_dir}"
        )

    # 确定目标文件路径
    if options.target:
        target_path = Path(options.target)
    else:
        # 使用默认输出目录
        default_output_dir = SQLFileUtils.get_output_dir() / "tmp"
        SQLFileUtils.ensure_directory(default_output_dir)
        target_path = default_output_dir / f"{source_path.name}.merged.auto.json"

    # 确保目标目录存在
    SQLFileUtils.ensure_directory(target_path.parent)

    # 读取并合并配置
    merged_config = {
        "table": {},
        "columns": {}
    }

    try:
        # 遍历所有JSON文件
        for file_path in source_path.glob("*.json"):
            format_name = file_path.stem  # 使用文件名（不含扩展名）作为格式名
            try:
                config = SQLFileUtils.read_json_file(file_path)

                # 合并table部分
                if "table" in config:
                    merged_config["table"][format_name] = config["table"]

                # 合并columns部分
                if "columns" in config:
                    for column_name, column_info in config["columns"].items():
                        if column_name not in merged_config["columns"]:
                            merged_config["columns"][column_name] = {}
                        merged_config["columns"][column_name][format_name] = column_info

            except json.JSONDecodeError:
                return MergeConfigResult(
                    success=False,
                    message=f"Invalid JSON file: {file_path}"
                )

        # 进行post处理
        merged_config = _post_process(source_path, merged_config)

        # 如果是dry run模式，直接返回结果
        if options.dry_run:
            return MergeConfigResult(
                success=True,
                message="Dry run completed successfully",
                data=merged_config
            )

        # 写入合并后的配置
        SQLFileUtils.write_json_file(target_path, merged_config)

        # 写入sql.json
        sql_json_path = source_path / "sql.json"
        if sql_json_path.exists():
            SQLFileUtils.write_json_file(sql_json_path, merged_config)

        return MergeConfigResult(
            success=True,
            message=f"Configuration merged successfully to {target_path}",
            data=merged_config
        )

    except Exception as e:
        return MergeConfigResult(
            success=False,
            message=f"Error merging configurations: {str(e)}"
        )